package org.liveboardgames.agricola.business;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.liveboardgames.agricola.access.IFarmDao;
import org.liveboardgames.agricola.business.helper.GameHelper;
import org.liveboardgames.agricola.business.updater.FarmTileUpdater;
import org.liveboardgames.agricola.business.updater.FarmUpdater;
import org.liveboardgames.agricola.controller.AgricolaUpdateAdapter;
import org.liveboardgames.agricola.domain.Change;
import org.liveboardgames.agricola.domain.farm.Farm;
import org.liveboardgames.agricola.domain.farm.FarmTile;
import org.liveboardgames.agricola.domain.farm.Pasture;
import org.liveboardgames.agricola.model.enums.ChangesEnum;
import org.liveboardgames.agricola.model.enums.ResourceTypeEnum;

public class PastureServiceImpl implements IPastureService {

  private IFarmDao farmDao;

  public void setFarmDao(IFarmDao farmDao) {
    this.farmDao = farmDao;
  }

  public void buildPasture(Long gameId, Long farmId, Set<Integer> tileIds) {
    Farm farm = farmDao.load(farmId);

    List<Change> changes = new ArrayList<Change>();

    GameHelper gameHelper = new GameHelper();
    Set<FarmTile> buildTiles = gameHelper.findFarmTiles(farm, tileIds);

    // Retrieve the IDs of the fences that are to be built
    // In fact here we only really need the number of fences that are built
    Set<Long> fencesIds = gameHelper.getNewFences(farm, buildTiles);
    // Compute the number of available fences
    Integer availableFences = gameHelper.computeAvailableFences(farm);
    if (availableFences < fencesIds.size()) {
      throw new IllegalArgumentException("Need to handle incorrect calls. Cannot build more than " + availableFences +
          " fences");
    }

    // Pay the fences
    // TODO: later on, we'll need other data like cards in play, that will
    // affect the cost
    Map<String, Integer> fencesCost = getFencesCost(fencesIds);
    new FarmUpdater(null, farm, changes).pay(fencesCost);

    // Build the new pasture. Hibernate will be in charge of giving it an ID
    Pasture pasture = new Pasture();
    for (FarmTile farmTile : buildTiles) {
      // And attach each farm tile to it
      new FarmTileUpdater(farmTile, changes).buildPasture(pasture);
    }

    // This is used by the popup to dynamically prevent the user from
    // constructing impossible pastures
    Change change = new Change(ChangesEnum.AVAILABLE_FENCES, availableFences);
    changes.add(change);

    // Save the changes
    farmDao.save(farm);

    // Publish the changes
    new AgricolaUpdateAdapter().publishGameUpdates(gameId, changes);
  }

  private Map<String, Integer> getFencesCost(Set<Long> fencesIds) {
    Map<String, Integer> cost = new HashMap<String, Integer>();
    cost.put(ResourceTypeEnum.WOOD, fencesIds.size());
    return cost;
  }

}
